fortify: add bit checking for open(at)?64 functions
This also adds _2-variants for these functions, for extra glorious
checking
Bug: 131861088
Test: mma
Change-Id: I80475ff4bb220c0c47894e9532426f53412f176f
diff --git a/libc/bionic/open.cpp b/libc/bionic/open.cpp
index 222e5d3..df5ab21 100644
--- a/libc/bionic/open.cpp
+++ b/libc/bionic/open.cpp
@@ -70,6 +70,7 @@
if (needs_mode(flags)) __fortify_fatal("open: called with O_CREAT/O_TMPFILE but no mode");
return __openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), 0);
}
+__strong_alias(__open64_2, __open_2);
int openat(int fd, const char *pathname, int flags, ...) {
mode_t mode = 0;
@@ -89,3 +90,4 @@
if (needs_mode(flags)) __fortify_fatal("open: called with O_CREAT/O_TMPFILE but no mode");
return __openat(fd, pathname, force_O_LARGEFILE(flags), 0);
}
+__strong_alias(__openat64_2, __openat_2);
diff --git a/libc/include/bits/fortify/fcntl.h b/libc/include/bits/fortify/fcntl.h
index e7f2c82..4bb441e 100644
--- a/libc/include/bits/fortify/fcntl.h
+++ b/libc/include/bits/fortify/fcntl.h
@@ -92,6 +92,52 @@
}
#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
+#if __ANDROID_API__ >= __ANDROID_API_R__
+int __open64_2(const char*, int) __INTRODUCED_IN(30);
+int __openat64_2(int, const char*, int) __INTRODUCED_IN(30);
+int __open64_real(const char* __path, int __flags, ...) __RENAME(open64);
+int __openat64_real(int, const char*, int, ...) __RENAME(openat64);
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+int open64(const char* pathname, int flags, mode_t modes, ...) __overloadable
+ __errorattr(__open_too_many_args_error);
+
+__BIONIC_FORTIFY_INLINE
+int open64(const char* const __pass_object_size pathname, int flags)
+ __overloadable
+ __clang_error_if(__open_modes_useful(flags), "'open64' " __open_too_few_args_error) {
+ return __open64_2(pathname, flags);
+}
+
+__BIONIC_FORTIFY_INLINE
+int open64(const char* const __pass_object_size pathname, int flags, mode_t modes)
+ __overloadable
+ __clang_warning_if(!__open_modes_useful(flags) && modes,
+ "'open64' " __open_useless_modes_warning) {
+ return __open64_real(pathname, flags, modes);
+}
+
+__BIONIC_ERROR_FUNCTION_VISIBILITY
+int openat64(int dirfd, const char* pathname, int flags, mode_t modes, ...)
+ __overloadable
+ __errorattr(__open_too_many_args_error);
+
+__BIONIC_FORTIFY_INLINE
+int openat64(int dirfd, const char* const __pass_object_size pathname, int flags)
+ __overloadable
+ __clang_error_if(__open_modes_useful(flags), "'openat64' " __open_too_few_args_error) {
+ return __openat64_2(dirfd, pathname, flags);
+}
+
+__BIONIC_FORTIFY_INLINE
+int openat64(int dirfd, const char* const __pass_object_size pathname, int flags, mode_t modes)
+ __overloadable
+ __clang_warning_if(!__open_modes_useful(flags) && modes,
+ "'openat64' " __open_useless_modes_warning) {
+ return __openat64_real(dirfd, pathname, flags, modes);
+}
+#endif /* __ANDROID_API__ >= __ANDROID_API_R__ */
+
#undef __open_too_many_args_error
#undef __open_too_few_args_error
#undef __open_useless_modes_warning
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 424c8f3..b12df56 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1482,6 +1482,8 @@
LIBC_R { # introduced=R
global:
+ __open64_2;
+ __openat64_2;
call_once;
cnd_broadcast;
cnd_destroy;
diff --git a/tests/clang_fortify_tests.cpp b/tests/clang_fortify_tests.cpp
index fa0797c..4c4e510 100644
--- a/tests/clang_fortify_tests.cpp
+++ b/tests/clang_fortify_tests.cpp
@@ -251,6 +251,50 @@
}
}
+FORTIFY_TEST(fcntl) {
+ const char target[] = "/dev/null";
+ int dirfd = 0;
+
+ // These all emit hard errors without diagnose_if, so running them is a bit
+ // more involved.
+#ifdef COMPILATION_TESTS
+ // expected-error@+1{{too many arguments}}
+ open("/", 0, 0, 0);
+ // expected-error@+1{{too many arguments}}
+ open64("/", 0, 0, 0);
+ // expected-error@+1{{too many arguments}}
+ openat(0, "/", 0, 0, 0);
+ // expected-error@+1{{too many arguments}}
+ openat64(0, "/", 0, 0, 0);
+#endif
+
+ // expected-error@+1{{missing mode}}
+ EXPECT_FORTIFY_DEATH(open(target, O_CREAT));
+ // expected-error@+1{{missing mode}}
+ EXPECT_FORTIFY_DEATH(open(target, O_TMPFILE));
+ // expected-error@+1{{missing mode}}
+ EXPECT_FORTIFY_DEATH(open64(target, O_CREAT));
+ // expected-error@+1{{missing mode}}
+ EXPECT_FORTIFY_DEATH(open64(target, O_TMPFILE));
+ // expected-error@+1{{missing mode}}
+ EXPECT_FORTIFY_DEATH(openat(dirfd, target, O_CREAT));
+ // expected-error@+1{{missing mode}}
+ EXPECT_FORTIFY_DEATH(openat(dirfd, target, O_TMPFILE));
+ // expected-error@+1{{missing mode}}
+ EXPECT_FORTIFY_DEATH(openat64(dirfd, target, O_CREAT));
+ // expected-error@+1{{missing mode}}
+ EXPECT_FORTIFY_DEATH(openat64(dirfd, target, O_TMPFILE));
+
+ // expected-warning@+1{{superfluous mode bits}}
+ EXPECT_NO_DEATH(open(target, O_RDONLY, 0777));
+ // expected-warning@+1{{superfluous mode bits}}
+ EXPECT_NO_DEATH(open64(target, O_RDONLY, 0777));
+ // expected-warning@+1{{superfluous mode bits}}
+ EXPECT_NO_DEATH(openat(dirfd, target, O_RDONLY, 0777));
+ // expected-warning@+1{{superfluous mode bits}}
+ EXPECT_NO_DEATH(openat64(dirfd, target, O_RDONLY, 0777));
+}
+
// Since these emit hard errors, it's sort of hard to run them...
#ifdef COMPILATION_TESTS
namespace compilation_tests {
@@ -259,49 +303,6 @@
__builtin_unreachable();
}
-static void testFcntl() {
- // expected-error@+1{{too many arguments}}
- open("/", 0, 0, 0);
-#if 0
- // expected-error@+1{{either with 2 or 3 arguments, not more}}
-#endif
- open64("/", 0, 0, 0);
- // expected-error@+1{{too many arguments}}
- openat(0, "/", 0, 0, 0);
-#if 0
- // expected-error@+1{{either with 3 or 4 arguments, not more}}
-#endif
- openat64(0, "/", 0, 0, 0);
-
- // expected-error@+1{{missing mode}}
- open("/", O_CREAT);
- // expected-error@+1{{missing mode}}
- open("/", O_TMPFILE);
-#if 0
- // expected-error@+1{{needs 3 arguments}}
-#endif
- open64("/", O_CREAT);
-#if 0
- // expected-error@+1{{needs 3 arguments}}
-#endif
- open64("/", O_TMPFILE);
- // expected-error@+1{{missing mode}}
- openat(0, "/", O_CREAT);
- // expected-error@+1{{missing mode}}
- openat(0, "/", O_TMPFILE);
-#if 0
- // expected-error@+1{{needs 4 arguments}}
-#endif
- openat64(0, "/", O_CREAT);
-#if 0
- // expected-error@+1{{needs 4 arguments}}
-#endif
- openat64(0, "/", O_TMPFILE);
-
- // Superfluous modes are sometimes bugs, but not often enough to complain
- // about, apparently.
-}
-
static void testFormatStrings() {
const auto unsigned_value = declval<unsigned long long>();
const auto* unknown_string = declval<const char*>();