add a fortified implementation of getcwd
Change-Id: Ice3e6d3e1ff07788305dc85f8ee4059baad5fac4
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
index f0de29e..904447c 100644
--- a/libc/include/unistd.h
+++ b/libc/include/unistd.h
@@ -224,6 +224,10 @@
} while (_rc == -1 && errno == EINTR); \
_rc; })
+extern char* __getcwd_chk(char*, size_t, size_t);
+__errordecl(__getcwd_dest_size_error, "getcwd called with size bigger than destination");
+extern char* __getcwd_real(char*, size_t) __RENAME(getcwd);
+
extern ssize_t __pread_chk(int, void*, size_t, off_t, size_t);
__errordecl(__pread_dest_size_error, "pread called with size bigger than destination");
__errordecl(__pread_count_toobig_error, "pread called with count > SSIZE_MAX");
@@ -251,6 +255,37 @@
#if defined(__BIONIC_FORTIFY)
+__BIONIC_FORTIFY_INLINE
+char* getcwd(char* buf, size_t size) {
+ size_t bos = __bos(buf);
+
+#if defined(__clang__)
+ /*
+ * Work around LLVM's incorrect __builtin_object_size implementation here
+ * to avoid needing the workaround in the __getcwd_chk ABI forever.
+ *
+ * https://llvm.org/bugs/show_bug.cgi?id=23277
+ */
+ if (buf == NULL) {
+ bos = __BIONIC_FORTIFY_UNKNOWN_SIZE;
+ }
+#else
+ if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
+ return __getcwd_real(buf, size);
+ }
+
+ if (__builtin_constant_p(size) && (size > bos)) {
+ __getcwd_dest_size_error();
+ }
+
+ if (__builtin_constant_p(size) && (size <= bos)) {
+ return __getcwd_real(buf, size);
+ }
+#endif
+
+ return __getcwd_chk(buf, size, bos);
+}
+
#if defined(__USE_FILE_OFFSET64)
#define __PREAD_PREFIX(x) __pread64_ ## x
#else