Merge "Remove a check for AIDs in the OEM range."
diff --git a/libc/bionic/fortify.cpp b/libc/bionic/fortify.cpp
index eaf5387..cbcc976 100644
--- a/libc/bionic/fortify.cpp
+++ b/libc/bionic/fortify.cpp
@@ -78,8 +78,6 @@
// http://gcc.gnu.org/ml/gcc-patches/2004-09/msg02055.html
//
-struct __bionic_zero_size_is_okay_t __bionic_zero_size_is_okay;
-
int __FD_ISSET_chk(int fd, fd_set* set, size_t set_size) {
__check_fd_set("FD_ISSET", fd, set_size);
return FD_ISSET(fd, set);
diff --git a/libc/bionic/open.cpp b/libc/bionic/open.cpp
index 6d179c4..222e5d3 100644
--- a/libc/bionic/open.cpp
+++ b/libc/bionic/open.cpp
@@ -43,6 +43,10 @@
#endif
}
+static inline bool needs_mode(int flags) {
+ return ((flags & O_CREAT) == O_CREAT) || ((flags & O_TMPFILE) == O_TMPFILE);
+}
+
int creat(const char* pathname, mode_t mode) {
return open(pathname, O_CREAT | O_TRUNC | O_WRONLY, mode);
}
@@ -51,7 +55,7 @@
int open(const char* pathname, int flags, ...) {
mode_t mode = 0;
- if ((flags & O_CREAT) != 0) {
+ if (needs_mode(flags)) {
va_list args;
va_start(args, flags);
mode = static_cast<mode_t>(va_arg(args, int));
@@ -63,17 +67,14 @@
__strong_alias(open64, open);
int __open_2(const char* pathname, int flags) {
- if (__predict_false((flags & O_CREAT) != 0)) {
- __fortify_fatal("open(O_CREAT): called without specifying a mode");
- }
-
+ 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);
}
int openat(int fd, const char *pathname, int flags, ...) {
mode_t mode = 0;
- if ((flags & O_CREAT) != 0) {
+ if (needs_mode(flags)) {
va_list args;
va_start(args, flags);
mode = static_cast<mode_t>(va_arg(args, int));
@@ -85,9 +86,6 @@
__strong_alias(openat64, openat);
int __openat_2(int fd, const char* pathname, int flags) {
- if ((flags & O_CREAT) != 0) {
- __fortify_fatal("openat(O_CREAT): called without specifying a mode");
- }
-
+ 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);
}
diff --git a/libc/include/bits/fortify/fcntl.h b/libc/include/bits/fortify/fcntl.h
index 3e0a590..6d90341 100644
--- a/libc/include/bits/fortify/fcntl.h
+++ b/libc/include/bits/fortify/fcntl.h
@@ -40,7 +40,10 @@
#if defined(__BIONIC_FORTIFY)
#define __open_too_many_args_error "too many arguments"
-#define __open_too_few_args_error "called with O_CREAT, but missing mode"
+#define __open_too_few_args_error "called with O_CREAT or O_TMPFILE, but missing mode"
+#define __open_useless_modes_warning "has superfluous mode bits; missing O_CREAT?"
+/* O_TMPFILE shares bits with O_DIRECTORY. */
+#define __open_modes_useful(flags) (((flags) & O_CREAT) || ((flags) & O_TMPFILE) == O_TMPFILE)
#if defined(__clang__)
#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
@@ -57,12 +60,15 @@
__BIONIC_FORTIFY_INLINE
int open(const char* const __pass_object_size pathname, int flags)
__overloadable
- __clang_error_if(flags & O_CREAT, "'open' " __open_too_few_args_error) {
+ __clang_error_if(__open_modes_useful(flags), "'open' " __open_too_few_args_error) {
return __open_2(pathname, flags);
}
__BIONIC_FORTIFY_INLINE
-int open(const char* const __pass_object_size pathname, int flags, mode_t modes) __overloadable {
+int open(const char* const __pass_object_size pathname, int flags, mode_t modes)
+ __overloadable
+ __clang_warning_if(!__open_modes_useful(flags) && modes,
+ "'open' " __open_useless_modes_warning) {
return __open_real(pathname, flags, modes);
}
@@ -72,16 +78,17 @@
__errorattr(__open_too_many_args_error);
__BIONIC_FORTIFY_INLINE
-int openat(int dirfd, const char* const __pass_object_size pathname,
- int flags)
+int openat(int dirfd, const char* const __pass_object_size pathname, int flags)
__overloadable
- __clang_error_if(flags & O_CREAT, "'openat' " __open_too_few_args_error) {
+ __clang_error_if(__open_modes_useful(flags), "'openat' " __open_too_few_args_error) {
return __openat_2(dirfd, pathname, flags);
}
__BIONIC_FORTIFY_INLINE
-int openat(int dirfd, const char* const __pass_object_size pathname, int flags,
- mode_t modes) __overloadable {
+int openat(int dirfd, const char* const __pass_object_size pathname, int flags, mode_t modes)
+ __overloadable
+ __clang_warning_if(!__open_modes_useful(flags) && modes,
+ "'openat' " __open_useless_modes_warning) {
return __openat_real(dirfd, pathname, flags, modes);
}
#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
@@ -94,7 +101,7 @@
__BIONIC_FORTIFY_INLINE
int open(const char* pathname, int flags, ...) {
if (__builtin_constant_p(flags)) {
- if ((flags & O_CREAT) && __builtin_va_arg_pack_len() == 0) {
+ if (__open_modes_useful(flags) && __builtin_va_arg_pack_len() == 0) {
__creat_missing_mode(); /* Compile time error. */
}
}
@@ -113,7 +120,7 @@
__BIONIC_FORTIFY_INLINE
int openat(int dirfd, const char* pathname, int flags, ...) {
if (__builtin_constant_p(flags)) {
- if ((flags & O_CREAT) && __builtin_va_arg_pack_len() == 0) {
+ if (__open_modes_useful(flags) && __builtin_va_arg_pack_len() == 0) {
__creat_missing_mode(); /* Compile time error. */
}
}
@@ -134,4 +141,6 @@
#undef __open_too_many_args_error
#undef __open_too_few_args_error
+#undef __open_useless_modes_warning
+#undef __open_modes_useful
#endif /* defined(__BIONIC_FORTIFY) */
diff --git a/libc/include/bits/fortify/string.h b/libc/include/bits/fortify/string.h
index 0c1999b..667e21d 100644
--- a/libc/include/bits/fortify/string.h
+++ b/libc/include/bits/fortify/string.h
@@ -37,37 +37,45 @@
size_t __strlcpy_chk(char*, const char*, size_t, size_t) __INTRODUCED_IN(17);
size_t __strlcat_chk(char*, const char*, size_t, size_t) __INTRODUCED_IN(17);
-/* Only used with FORTIFY, but some headers that need it undef FORTIFY, so we
- * have the definition out here.
- */
-struct __bionic_zero_size_is_okay_t {};
-
#if defined(__BIONIC_FORTIFY)
// These can share their implementation between gcc and clang with minimal
// trickery...
#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
__BIONIC_FORTIFY_INLINE
-void* memcpy(void* const dst __pass_object_size0, const void* src, size_t copy_amount)
- __overloadable {
+void* memcpy(void* const dst __pass_object_size0, const void* src, size_t copy_amount)
+ __overloadable
+ __clang_error_if(__bos0(dst) != __BIONIC_FORTIFY_UNKNOWN_SIZE && __bos0(dst) < copy_amount,
+ "'memcpy' called with size bigger than buffer") {
return __builtin___memcpy_chk(dst, src, copy_amount, __bos0(dst));
}
__BIONIC_FORTIFY_INLINE
-void* memmove(void* const dst __pass_object_size0, const void* src, size_t len) __overloadable {
+void* memmove(void* const dst __pass_object_size0, const void* src, size_t len)
+ __overloadable
+ __clang_error_if(__bos0(dst) != __BIONIC_FORTIFY_UNKNOWN_SIZE && __bos0(dst) < len,
+ "'memmove' called with size bigger than buffer") {
return __builtin___memmove_chk(dst, src, len, __bos0(dst));
}
#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
#if __ANDROID_API__ >= __ANDROID_API_L__
__BIONIC_FORTIFY_INLINE
-char* stpcpy(char* const dst __pass_object_size, const char* src) __overloadable {
+char* stpcpy(char* const dst __pass_object_size, const char* src)
+ __overloadable
+ __clang_error_if(__bos(dst) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+ __bos(dst) <= __builtin_strlen(src),
+ "'stpcpy' called with string bigger than buffer") {
return __builtin___stpcpy_chk(dst, src, __bos(dst));
}
#endif /* __ANDROID_API__ >= __ANDROID_API_L__ */
#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
__BIONIC_FORTIFY_INLINE
-char* strcpy(char* const dst __pass_object_size, const char* src) __overloadable {
+char* strcpy(char* const dst __pass_object_size, const char* src)
+ __overloadable
+ __clang_error_if(__bos(dst) != __BIONIC_FORTIFY_UNKNOWN_SIZE &&
+ __bos(dst) <= __builtin_strlen(src),
+ "'strcpy' called with string bigger than buffer") {
return __builtin___strcpy_chk(dst, src, __bos(dst));
}
@@ -82,7 +90,12 @@
}
__BIONIC_FORTIFY_INLINE
-void* memset(void* const s __pass_object_size0, int c, size_t n) __overloadable {
+void* memset(void* const s __pass_object_size0, int c, size_t n)
+ __overloadable
+ __clang_error_if(__bos0(s) != __BIONIC_FORTIFY_UNKNOWN_SIZE && __bos0(s) < n,
+ "'memset' called with size bigger than buffer")
+ /* If you're a user who wants this warning to go away: use `(&memset)(foo, bar, baz)`. */
+ __clang_warning_if(c && !n, "'memset' will set 0 bytes; maybe the arguments got flipped?") {
return __builtin___memset_chk(s, c, n, __bos0(s));
}
#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
@@ -90,35 +103,9 @@
#if defined(__clang__)
-#define __error_if_overflows_dst(name, dst, n, what) \
- __enable_if(__bos0(dst) != __BIONIC_FORTIFY_UNKNOWN_SIZE && \
- __bos0(dst) < (n), "selected when the buffer is too small") \
- __errorattr(#name " called with " what " bigger than buffer")
-
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-void* memcpy(void* dst, const void* src, size_t copy_amount) __overloadable
- __error_if_overflows_dst(memcpy, dst, copy_amount, "size");
-
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-void* memmove(void *dst, const void* src, size_t len) __overloadable
- __error_if_overflows_dst(memmove, dst, len, "size");
-
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-void* memset(void* s, int c, size_t n) __overloadable
- __error_if_overflows_dst(memset, s, n, "size");
-
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-char* stpcpy(char* dst, const char* src) __overloadable
- __error_if_overflows_dst(stpcpy, dst, __builtin_strlen(src), "string");
-
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-char* strcpy(char* dst, const char* src) __overloadable
- __error_if_overflows_dst(strcpy, dst, __builtin_strlen(src), "string");
-
#if __ANDROID_API__ >= __ANDROID_API_M__
__BIONIC_FORTIFY_INLINE
-void* memchr(const void* const s __pass_object_size, int c, size_t n)
- __overloadable {
+void* memchr(const void* const s __pass_object_size, int c, size_t n) __overloadable {
size_t bos = __bos(s);
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
@@ -129,8 +116,7 @@
}
__BIONIC_FORTIFY_INLINE
-void* memrchr(const void* const s __pass_object_size, int c, size_t n)
- __overloadable {
+void* memrchr(const void* const s __pass_object_size, int c, size_t n) __overloadable {
size_t bos = __bos(s);
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
@@ -173,8 +159,7 @@
#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
__BIONIC_FORTIFY_INLINE
-size_t strlcpy(char* const dst __pass_object_size, const char* src, size_t size)
- __overloadable {
+size_t strlcpy(char* const dst __pass_object_size, const char* src, size_t size) __overloadable {
size_t bos = __bos(dst);
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
@@ -185,8 +170,7 @@
}
__BIONIC_FORTIFY_INLINE
-size_t strlcat(char* const dst __pass_object_size, const char* src, size_t size)
- __overloadable {
+size_t strlcat(char* const dst __pass_object_size, const char* src, size_t size) __overloadable {
size_t bos = __bos(dst);
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
@@ -210,15 +194,13 @@
}
__BIONIC_FORTIFY_INLINE
-size_t strlen(const char* const s __pass_object_size0)
- __overloadable {
+size_t strlen(const char* const s __pass_object_size0) __overloadable {
size_t bos = __bos0(s);
if (bos == __BIONIC_FORTIFY_UNKNOWN_SIZE) {
return __builtin_strlen(s);
}
- // return __builtin_strlen(s);
return __strlen_chk(s, bos);
}
#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
@@ -247,38 +229,6 @@
}
#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR2__ */
-#if __ANDROID_API__ >= __ANDROID_API_J_MR1__
-/* In *many* cases, memset(foo, sizeof(foo), 0) is a mistake where the user has
- * flipped the size + value arguments. However, there may be cases (e.g. with
- * macros) where it's okay for the size to fold to zero. We should warn on this,
- * but we should also provide a FORTIFY'ed escape hatch.
- */
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-void* memset(void* s, int c, size_t n, struct __bionic_zero_size_is_okay_t ok)
- __overloadable
- __error_if_overflows_dst(memset, s, n, "size");
-
-__BIONIC_FORTIFY_INLINE
-void* memset(void* const s __pass_object_size0, int c, size_t n, struct __bionic_zero_size_is_okay_t ok __attribute__((unused)))
- __overloadable {
- return __builtin___memset_chk(s, c, n, __bos0(s));
-}
-
-extern struct __bionic_zero_size_is_okay_t __bionic_zero_size_is_okay;
-/* We verify that `c` is non-zero, because as pointless as memset(foo, 0, 0) is,
- * flipping size + count will do nothing.
- */
-__BIONIC_ERROR_FUNCTION_VISIBILITY
-void* memset(void* s, int c, size_t n) __overloadable
- __enable_if(c && !n, "selected when we'll set zero bytes")
- __RENAME_CLANG(memset)
- __warnattr_real("will set 0 bytes; maybe the arguments got flipped? "
- "(Add __bionic_zero_size_is_okay as a fourth argument "
- "to silence this.)");
-#endif /* __ANDROID_API__ >= __ANDROID_API_J_MR1__ */
-
-#undef __error_zero_size
-#undef __error_if_overflows_dst
#else // defined(__clang__)
extern char* __strncpy_real(char*, const char*, size_t) __RENAME(strncpy);
extern void* __memrchr_real(const void*, int, size_t) __RENAME(memrchr);
diff --git a/libc/include/sched.h b/libc/include/sched.h
index d407202..b8ef44b 100644
--- a/libc/include/sched.h
+++ b/libc/include/sched.h
@@ -25,6 +25,7 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
#ifndef _SCHED_H_
#define _SCHED_H_
@@ -41,22 +42,22 @@
int sched_priority;
};
-int sched_setscheduler(pid_t, int, const struct sched_param*);
-int sched_getscheduler(pid_t);
+int sched_setscheduler(pid_t pid, int policy, const struct sched_param* param);
+int sched_getscheduler(pid_t pid);
int sched_yield(void);
-int sched_get_priority_max(int);
-int sched_get_priority_min(int);
-int sched_setparam(pid_t, const struct sched_param*);
-int sched_getparam(pid_t, struct sched_param*);
-int sched_rr_get_interval(pid_t, struct timespec*);
+int sched_get_priority_max(int policy);
+int sched_get_priority_min(int policy);
+int sched_setparam(pid_t pid, const struct sched_param* param);
+int sched_getparam(pid_t pid, struct sched_param* param);
+int sched_rr_get_interval(pid_t pid, struct timespec* quantum);
#if defined(__USE_GNU)
-int clone(int (*)(void*), void*, int, void*, ...) __INTRODUCED_IN_ARM(9)
- __INTRODUCED_IN_MIPS(12) __INTRODUCED_IN_X86(17);
-int unshare(int) __INTRODUCED_IN(17);
+int clone(int (*fn)(void*), void* child_stack, int flags, void* arg, ...)
+ __INTRODUCED_IN_ARM(9) __INTRODUCED_IN_MIPS(12) __INTRODUCED_IN_X86(17);
+int unshare(int flags) __INTRODUCED_IN(17);
int sched_getcpu(void) __INTRODUCED_IN(12);
-int setns(int, int) __INTRODUCED_IN(21);
+int setns(int fd, int ns_type) __INTRODUCED_IN(21);
#ifdef __LP64__
#define CPU_SETSIZE 1024
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index 7e5a976..4dff48d 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -153,8 +153,8 @@
* Allow users to just use dprintf and vfdprintf on any version by renaming those calls to their
* legacy equivalents if needed.
*/
-int dprintf(int, const char*, ...) __printflike(2, 3) __RENAME(fdprintf);
-int vdprintf(int, const char*, va_list) __printflike(2, 0) __RENAME(vfdprintf);
+int dprintf(int, const char*, ...) __RENAME(fdprintf) __printflike(2, 3);
+int vdprintf(int, const char*, va_list) __RENAME(vfdprintf) __printflike(2, 0);
#endif
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ < 201112L) || \
diff --git a/libc/include/syslog.h b/libc/include/syslog.h
index 8000f03..a320352 100644
--- a/libc/include/syslog.h
+++ b/libc/include/syslog.h
@@ -50,28 +50,29 @@
#define LOG_MAKEPRI(fac, pri) ((fac) | (pri))
/* Facilities are currently ignored on Android. */
-#define LOG_KERN 0000
-#define LOG_USER 0010
-#define LOG_MAIL 0020
-#define LOG_DAEMON 0030
-#define LOG_AUTH 0040
-#define LOG_SYSLOG 0050
-#define LOG_LPR 0060
-#define LOG_NEWS 0070
-#define LOG_UUCP 0100
-#define LOG_CRON 0110
-#define LOG_AUTHPRIV 0120
-#define LOG_FTP 0130
-#define LOG_LOCAL0 0200
-#define LOG_LOCAL1 0210
-#define LOG_LOCAL2 0220
-#define LOG_LOCAL3 0230
-#define LOG_LOCAL4 0240
-#define LOG_LOCAL5 0250
-#define LOG_LOCAL6 0260
-#define LOG_LOCAL7 0270
+#define LOG_KERN (0<<3)
+#define LOG_USER (1<<3)
+#define LOG_MAIL (2<<3)
+#define LOG_DAEMON (3<<3)
+#define LOG_AUTH (4<<3)
+#define LOG_SYSLOG (5<<3)
+#define LOG_LPR (6<<3)
+#define LOG_NEWS (7<<3)
+#define LOG_UUCP (8<<3)
+#define LOG_CRON (9<<3)
+#define LOG_AUTHPRIV (10<<3)
+#define LOG_FTP (11<<3)
+#define LOG_LOCAL0 (16<<3)
+#define LOG_LOCAL1 (17<<3)
+#define LOG_LOCAL2 (18<<3)
+#define LOG_LOCAL3 (19<<3)
+#define LOG_LOCAL4 (20<<3)
+#define LOG_LOCAL5 (21<<3)
+#define LOG_LOCAL6 (22<<3)
+#define LOG_LOCAL7 (23<<3)
-#define LOG_FACMASK 01770
+#define LOG_NFACILITIES 24
+#define LOG_FACMASK 0x3f8
#define LOG_FAC(x) (((x) >> 3) & (LOG_FACMASK >> 3))
#define LOG_MASK(pri) (1 << (pri))
diff --git a/linker/Android.bp b/linker/Android.bp
index efd91ac..fda7eb5 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -101,6 +101,12 @@
"-Werror",
],
+ product_variables: {
+ debuggable: {
+ cppflags: ["-DUSE_LD_CONFIG_FILE"],
+ },
+ },
+
cppflags: ["-Wold-style-cast"],
// we are going to link libc++_static manually because
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 8e7a141..a212624 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -558,9 +558,10 @@
static LoadTask* create(const char* name,
soinfo* needed_by,
+ android_namespace_t* start_from,
std::unordered_map<const soinfo*, ElfReader>* readers_map) {
LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
- return new (ptr) LoadTask(name, needed_by, readers_map);
+ return new (ptr) LoadTask(name, needed_by, start_from, readers_map);
}
const char* get_name() const {
@@ -612,6 +613,11 @@
is_dt_needed_ = is_dt_needed;
}
+ // returns the namespace from where we need to start loading this.
+ const android_namespace_t* get_start_from() const {
+ return start_from_;
+ }
+
const ElfReader& get_elf_reader() const {
CHECK(si_ != nullptr);
return (*elf_readers_map_)[si_];
@@ -650,10 +656,11 @@
private:
LoadTask(const char* name,
soinfo* needed_by,
+ android_namespace_t* start_from,
std::unordered_map<const soinfo*, ElfReader>* readers_map)
: name_(name), needed_by_(needed_by), si_(nullptr),
fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
- is_dt_needed_(false) {}
+ is_dt_needed_(false), start_from_(start_from) {}
~LoadTask() {
if (fd_ != -1 && close_fd_) {
@@ -672,6 +679,7 @@
// TODO(dimitry): needed by workaround for http://b/26394120 (the grey-list)
bool is_dt_needed_;
// END OF WORKAROUND
+ const android_namespace_t* const start_from_;
DISALLOW_IMPLICIT_CONSTRUCTORS(LoadTask);
};
@@ -1041,7 +1049,7 @@
ZipArchiveCache* zip_archive_cache,
const char* name, soinfo *needed_by,
off64_t* file_offset, std::string* realpath) {
- TRACE("[ opening %s ]", name);
+ TRACE("[ opening %s at namespace %s]", name, ns->get_name());
// If the name contains a slash, we should attempt to open it directly and not search the paths.
if (strchr(name, '/') != nullptr) {
@@ -1273,7 +1281,7 @@
}
for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
- load_tasks->push_back(LoadTask::create(name, si, task->get_readers_map()));
+ load_tasks->push_back(LoadTask::create(name, si, ns, task->get_readers_map()));
});
return true;
@@ -1368,8 +1376,7 @@
}
static bool find_library_in_linked_namespace(const android_namespace_link_t& namespace_link,
- LoadTask* task,
- int rtld_flags) {
+ LoadTask* task) {
android_namespace_t* ns = namespace_link.linked_namespace();
soinfo* candidate;
@@ -1394,29 +1401,10 @@
return true;
}
- // try to load the library - once namespace boundary is crossed
- // we need to load a library within separate load_group
- // to avoid using symbols from foreign namespace while.
- //
- // All symbols during relocation should be resolved within a
- // namespace to preserve library locality to a namespace.
- const char* name = task->get_name();
- if (find_libraries(ns,
- task->get_needed_by(),
- &name,
- 1,
- &candidate,
- nullptr /* ld_preloads */,
- 0 /* ld_preload_count*/,
- rtld_flags,
- nullptr /* extinfo*/,
- false /* add_as_children */,
- false /* search_linked_namespaces */)) {
- task->set_soinfo(candidate);
- return true;
- }
-
- return false;
+ // returning true with empty soinfo means that the library is okay to be
+ // loaded in the namespace buy has not yet been loaded there before.
+ task->set_soinfo(nullptr);
+ return true;
}
static bool find_library_internal(android_namespace_t* ns,
@@ -1445,9 +1433,24 @@
// if a library was not found - look into linked namespaces
for (auto& linked_namespace : ns->linked_namespaces()) {
if (find_library_in_linked_namespace(linked_namespace,
- task,
- rtld_flags)) {
- return true;
+ task)) {
+ if (task->get_soinfo() == nullptr) {
+ // try to load the library - once namespace boundary is crossed
+ // we need to load a library within separate load_group
+ // to avoid using symbols from foreign namespace while.
+ //
+ // However, actual linking is deferred until when the global group
+ // is fully identified and is applied to all namespaces.
+ // Otherwise, the libs in the linked namespace won't get symbols from
+ // the global group.
+ if (load_library(linked_namespace.linked_namespace(), task, zip_archive_cache, load_tasks, rtld_flags, false)) {
+ return true;
+ }
+ // lib was not found in the namespace. Try next linked namespace.
+ } else {
+ // lib is already loaded
+ return true;
+ }
}
}
}
@@ -1458,44 +1461,6 @@
static void soinfo_unload(soinfo* si);
static void soinfo_unload(soinfo* soinfos[], size_t count);
-// TODO: this is slightly unusual way to construct
-// the global group for relocation. Not every RTLD_GLOBAL
-// library is included in this group for backwards-compatibility
-// reasons.
-//
-// This group consists of the main executable, LD_PRELOADs
-// and libraries with the DF_1_GLOBAL flag set.
-static soinfo_list_t make_global_group(android_namespace_t* ns) {
- soinfo_list_t global_group;
- ns->soinfo_list().for_each([&](soinfo* si) {
- if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
- global_group.push_back(si);
- }
- });
-
- return global_group;
-}
-
-// This function provides a list of libraries to be shared
-// by the namespace. For the default namespace this is the global
-// group (see make_global_group). For all others this is a group
-// of RTLD_GLOBAL libraries (which includes the global group from
-// the default namespace).
-static soinfo_list_t get_shared_group(android_namespace_t* ns) {
- if (ns == &g_default_namespace) {
- return make_global_group(ns);
- }
-
- soinfo_list_t shared_group;
- ns->soinfo_list().for_each([&](soinfo* si) {
- if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) {
- shared_group.push_back(si);
- }
- });
-
- return shared_group;
-}
-
static void shuffle(std::vector<LoadTask*>* v) {
for (size_t i = 0, size = v->size(); i < size; ++i) {
size_t n = size - i;
@@ -1518,19 +1483,17 @@
int rtld_flags,
const android_dlextinfo* extinfo,
bool add_as_children,
- bool search_linked_namespaces) {
+ bool search_linked_namespaces,
+ std::unordered_map<const soinfo*, ElfReader>& readers_map,
+ std::vector<android_namespace_t*>* namespaces) {
// Step 0: prepare.
LoadTaskList load_tasks;
- std::unordered_map<const soinfo*, ElfReader> readers_map;
for (size_t i = 0; i < library_names_count; ++i) {
const char* name = library_names[i];
- load_tasks.push_back(LoadTask::create(name, start_with, &readers_map));
+ load_tasks.push_back(LoadTask::create(name, start_with, ns, &readers_map));
}
- // Construct global_group.
- soinfo_list_t global_group = make_global_group(ns);
-
// If soinfos array is null allocate one on stack.
// The array is needed in case of failure; for example
// when library_names[] = {libone.so, libtwo.so} and libone.so
@@ -1570,7 +1533,12 @@
task->set_extinfo(is_dt_needed ? nullptr : extinfo);
task->set_dt_needed(is_dt_needed);
- if (!find_library_internal(ns,
+ // try to find the load.
+ // Note: start from the namespace that is stored in the LoadTask. This namespace
+ // is different from the current namespace when the LoadTask is for a transitive
+ // dependency and the lib that created the LoadTask is not found in the
+ // current namespace but in one of the linked namespace.
+ if (!find_library_internal(const_cast<android_namespace_t*>(task->get_start_from()),
task,
&zip_archive_cache,
&load_tasks,
@@ -1629,18 +1597,61 @@
}
}
- // Step 4: Add LD_PRELOADed libraries to the global group for
- // future runs. There is no need to explicitly add them to
- // the global group for this run because they are going to
- // appear in the local group in the correct order.
+ // Step 4: Construct the global group. Note: DF_1_GLOBAL bit of a library is
+ // determined at step 3.
+
+ // Step 4-1: DF_1_GLOBAL bit is force set for LD_PRELOADed libs because they
+ // must be added to the global group
if (ld_preloads != nullptr) {
for (auto&& si : *ld_preloads) {
si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
}
}
+ // Step 4-2: Gather all DF_1_GLOBAL libs which were newly loaded during this
+ // run. These will be the new member of the global group
+ soinfo_list_t new_global_group_members;
+ for (auto&& task : load_tasks) {
+ soinfo* si = task->get_soinfo();
+ if (!si->is_linked() && (si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
+ new_global_group_members.push_back(si);
+ }
+ }
- // Step 5: link libraries.
+ // Step 4-3: Add the new global group members to all the linked namespaces
+ for (auto si : new_global_group_members) {
+ for (auto linked_ns : *namespaces) {
+ if (si->get_primary_namespace() != linked_ns) {
+ linked_ns->add_soinfo(si);
+ si->add_secondary_namespace(linked_ns);
+ }
+ }
+ }
+
+ // Step 5: link libraries that are not destined to this namespace.
+ // Do this by recursively calling find_libraries on the namespace where the lib
+ // was found during Step 1.
+ for (auto&& task : load_tasks) {
+ soinfo* si = task->get_soinfo();
+ if (si->get_primary_namespace() != ns) {
+ const char* name = task->get_name();
+ if (find_libraries(si->get_primary_namespace(), task->get_needed_by(), &name, 1,
+ nullptr /* soinfos */, nullptr /* ld_preloads */, 0 /* ld_preload_count */,
+ rtld_flags, nullptr /* extinfo */, false /* add_as_children */,
+ false /* search_linked_namespaces */, readers_map, namespaces)) {
+ // If this lib is directly needed by one of the libs in this namespace,
+ // then increment the count
+ soinfo* needed_by = task->get_needed_by();
+ if (needed_by != nullptr && needed_by->get_primary_namespace() == ns && si->is_linked()) {
+ si->increment_ref_count();
+ }
+ } else {
+ return false;
+ }
+ }
+ }
+
+ // Step 6: link libraries in this namespace
soinfo_list_t local_group;
walk_dependencies_tree(
(start_with != nullptr && add_as_children) ? &start_with : soinfos,
@@ -1654,6 +1665,7 @@
}
});
+ soinfo_list_t global_group = ns->get_global_group();
bool linked = local_group.visit([&](soinfo* si) {
if (!si->is_linked()) {
if (!si->link_image(global_group, local_group, extinfo) ||
@@ -1684,6 +1696,9 @@
soinfo* needed_by) {
soinfo* si;
+ // readers_map is shared across recursive calls to find_libraries.
+ // However, the map is not shared across different threads.
+ std::unordered_map<const soinfo*, ElfReader> readers_map;
if (name == nullptr) {
si = solist_get_somain();
} else if (!find_libraries(ns,
@@ -1696,7 +1711,8 @@
rtld_flags,
extinfo,
false /* add_as_children */,
- true /* search_linked_namespaces */)) {
+ true /* search_linked_namespaces */,
+ readers_map)) {
return nullptr;
}
@@ -2208,7 +2224,7 @@
}
} else {
// If not shared - copy only the shared group
- add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
+ add_soinfos_to_namespace(parent_namespace->get_shared_group(), ns);
}
ns->set_ld_library_paths(std::move(ld_library_paths));
@@ -3413,7 +3429,7 @@
return true;
}
-static void init_default_namespace_no_config(bool is_asan) {
+static std::vector<android_namespace_t*> init_default_namespace_no_config(bool is_asan) {
g_default_namespace.set_isolated(false);
auto default_ld_paths = is_asan ? kAsanDefaultLdPaths : kDefaultLdPaths;
@@ -3428,9 +3444,13 @@
}
g_default_namespace.set_default_library_paths(std::move(ld_default_paths));
+
+ std::vector<android_namespace_t*> namespaces;
+ namespaces.push_back(&g_default_namespace);
+ return namespaces;
}
-void init_default_namespace(const char* executable_path) {
+std::vector<android_namespace_t*> init_default_namespaces(const char* executable_path) {
g_default_namespace.set_name("(default)");
soinfo* somain = solist_get_somain();
@@ -3447,14 +3467,24 @@
std::string error_msg;
- if (!Config::read_binary_config(kLdConfigFilePath,
+ const char* config_file = kLdConfigFilePath;
+#ifdef USE_LD_CONFIG_FILE
+ // This is a debugging/testing only feature. Must not be available on
+ // production builds.
+ const char* ld_config_file = getenv("LD_CONFIG_FILE");
+ if (ld_config_file != nullptr && file_exists(ld_config_file)) {
+ config_file = ld_config_file;
+ }
+#endif
+
+ if (!Config::read_binary_config(config_file,
executable_path,
g_is_asan,
&config,
&error_msg)) {
if (!error_msg.empty()) {
DL_WARN("error reading config file \"%s\" for \"%s\" (will use default configuration): %s",
- kLdConfigFilePath,
+ config_file,
executable_path,
error_msg.c_str());
}
@@ -3462,8 +3492,7 @@
}
if (config == nullptr) {
- init_default_namespace_no_config(g_is_asan);
- return;
+ return init_default_namespace_no_config(g_is_asan);
}
const auto& namespace_configs = config->namespace_configs();
@@ -3514,10 +3543,17 @@
soinfo* ld_android_so = solist_get_head();
for (auto it : namespaces) {
it.second->add_soinfo(ld_android_so);
- // TODO (dimitry): somain and ld_preloads should probably be added to all of these namespaces too?
+ // somain and ld_preloads are added to these namespaces after LD_PRELOAD libs are linked
}
set_application_target_sdk_version(config->target_sdk_version());
+
+ std::vector<android_namespace_t*> created_namespaces;
+ created_namespaces.reserve(namespaces.size());
+ for (auto kv : namespaces) {
+ created_namespaces.push_back(kv.second);
+ }
+ return created_namespaces;
}
// This function finds a namespace exported in ld.config.txt by its name.
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index bcb2281..54593e4 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -341,12 +341,19 @@
somain = si;
- init_default_namespace(executable_path);
+ std::vector<android_namespace_t*> namespaces = init_default_namespaces(executable_path);
if (!si->prelink_image()) __linker_cannot_link(g_argv[0]);
// add somain to global group
si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
+ // ... and add it to all other linked namespaces
+ for (auto linked_ns : namespaces) {
+ if (linked_ns != &g_default_namespace) {
+ linked_ns->add_soinfo(somain);
+ somain->add_secondary_namespace(linked_ns);
+ }
+ }
// Load ld_preloads and dependencies.
std::vector<const char*> needed_library_name_list;
@@ -364,6 +371,9 @@
const char** needed_library_names = &needed_library_name_list[0];
size_t needed_libraries_count = needed_library_name_list.size();
+ // readers_map is shared across recursive calls to find_libraries so that we
+ // don't need to re-load elf headers.
+ std::unordered_map<const soinfo*, ElfReader> readers_map;
if (needed_libraries_count > 0 &&
!find_libraries(&g_default_namespace,
si,
@@ -375,7 +385,9 @@
RTLD_GLOBAL,
nullptr,
true /* add_as_children */,
- true /* search_linked_namespaces */)) {
+ true /* search_linked_namespaces */,
+ readers_map,
+ &namespaces)) {
__linker_cannot_link(g_argv[0]);
} else if (needed_libraries_count == 0) {
if (!si->link_image(g_empty_list, soinfo_list_t::make_list(si), nullptr)) {
diff --git a/linker/linker_main.h b/linker/linker_main.h
index 8f3f07c..2cf30c2 100644
--- a/linker/linker_main.h
+++ b/linker/linker_main.h
@@ -31,6 +31,9 @@
#include <android/dlext.h>
+#include <unordered_map>
+#include <vector>
+
#include "linker_namespaces.h"
#include "linker_soinfo.h"
@@ -44,7 +47,9 @@
static size_t ref_count_;
};
-void init_default_namespace(const char* executable_path);
+class ElfReader;
+
+std::vector<android_namespace_t*> init_default_namespaces(const char* executable_path);
soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
struct stat* file_stat, off64_t file_offset,
uint32_t rtld_flags);
@@ -59,7 +64,9 @@
int rtld_flags,
const android_dlextinfo* extinfo,
bool add_as_children,
- bool search_linked_namespaces);
+ bool search_linked_namespaces,
+ std::unordered_map<const soinfo*, ElfReader>& readers_map,
+ std::vector<android_namespace_t*>* namespaces = nullptr);
void solist_add_soinfo(soinfo* si);
bool solist_remove_soinfo(soinfo* si);
diff --git a/linker/linker_namespaces.cpp b/linker/linker_namespaces.cpp
index 3c86f99..9fdf0b5 100644
--- a/linker/linker_namespaces.cpp
+++ b/linker/linker_namespaces.cpp
@@ -31,6 +31,8 @@
#include "linker_soinfo.h"
#include "linker_utils.h"
+#include <dlfcn.h>
+
bool android_namespace_t::is_accessible(const std::string& file) {
if (!is_isolated_) {
return true;
@@ -86,3 +88,41 @@
return !is_accessible_ftor(si);
});
}
+
+// TODO: this is slightly unusual way to construct
+// the global group for relocation. Not every RTLD_GLOBAL
+// library is included in this group for backwards-compatibility
+// reasons.
+//
+// This group consists of the main executable, LD_PRELOADs
+// and libraries with the DF_1_GLOBAL flag set.
+soinfo_list_t android_namespace_t::get_global_group() {
+ soinfo_list_t global_group;
+ soinfo_list().for_each([&](soinfo* si) {
+ if ((si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
+ global_group.push_back(si);
+ }
+ });
+
+ return global_group;
+}
+
+// This function provides a list of libraries to be shared
+// by the namespace. For the default namespace this is the global
+// group (see get_global_group). For all others this is a group
+// of RTLD_GLOBAL libraries (which includes the global group from
+// the default namespace).
+soinfo_list_t android_namespace_t::get_shared_group() {
+ if (this == &g_default_namespace) {
+ return get_global_group();
+ }
+
+ soinfo_list_t shared_group;
+ soinfo_list().for_each([&](soinfo* si) {
+ if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) {
+ shared_group.push_back(si);
+ }
+ });
+
+ return shared_group;
+}
diff --git a/linker/linker_namespaces.h b/linker/linker_namespaces.h
index 1099b6b..16906d6 100644
--- a/linker/linker_namespaces.h
+++ b/linker/linker_namespaces.h
@@ -136,6 +136,9 @@
// or one of it's parent soinfos belongs to this namespace.
bool is_accessible(soinfo* si);
+ soinfo_list_t get_global_group();
+ soinfo_list_t get_shared_group();
+
private:
const char* name_;
bool is_isolated_;
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 42c29c8..a9873c4 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -147,8 +147,9 @@
}
bool ElfReader::Read(const char* name, int fd, off64_t file_offset, off64_t file_size) {
- CHECK(!did_read_);
- CHECK(!did_load_);
+ if (did_read_) {
+ return true;
+ }
name_ = name;
fd_ = fd;
file_offset_ = file_offset;
@@ -167,7 +168,9 @@
bool ElfReader::Load(const android_dlextinfo* extinfo) {
CHECK(did_read_);
- CHECK(!did_load_);
+ if (did_load_) {
+ return true;
+ }
if (ReserveAddressSpace(extinfo) &&
LoadSegments() &&
FindPhdr()) {
diff --git a/tests/Android.bp b/tests/Android.bp
index 8f1c11f..084d393 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -298,7 +298,13 @@
"libLLVMSupport",
],
}
- }
+ },
+
+ product_variables: {
+ debuggable: {
+ cppflags: ["-DUSE_LD_CONFIG_FILE"],
+ },
+ },
}
// -----------------------------------------------------------------------------
@@ -592,6 +598,12 @@
sanitize: {
never: false,
},
+
+ product_variables: {
+ debuggable: {
+ cppflags: ["-DUSE_LD_CONFIG_FILE"],
+ },
+ },
}
subdirs = ["libs"]
diff --git a/tests/dl_test.cpp b/tests/dl_test.cpp
index aa8bd57..857640a 100644
--- a/tests/dl_test.cpp
+++ b/tests/dl_test.cpp
@@ -23,6 +23,8 @@
#include <stdint.h>
#include <string>
+#include <iostream>
+#include <fstream>
#include "gtest_globals.h"
#include "utils.h"
@@ -109,4 +111,131 @@
#endif
}
-// TODO: Add tests for LD_PRELOADs
+
+TEST(dl, exec_without_ld_preload) {
+#if defined(__BIONIC__)
+ std::string helper = get_testlib_root() +
+ "/ld_preload_test_helper/ld_preload_test_helper";
+ chmod(helper.c_str(), 0755);
+ ExecTestHelper eth;
+ eth.SetArgs({ helper.c_str(), nullptr });
+ eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, "12345");
+#endif
+}
+
+TEST(dl, exec_with_ld_preload) {
+#if defined(__BIONIC__)
+ std::string helper = get_testlib_root() +
+ "/ld_preload_test_helper/ld_preload_test_helper";
+ std::string env = std::string("LD_PRELOAD=") + get_testlib_root() + "/ld_preload_test_helper_lib2.so";
+ chmod(helper.c_str(), 0755);
+ ExecTestHelper eth;
+ eth.SetArgs({ helper.c_str(), nullptr });
+ eth.SetEnv({ env.c_str(), nullptr });
+ // ld_preload_test_helper calls get_value_from_lib() and returns the value.
+ // The symbol is defined by two libs: ld_preload_test_helper_lib.so and
+ // ld_preloaded_lib.so. The former is DT_NEEDED and the latter is LD_PRELOADED
+ // via this execution. The main executable is linked to the LD_PRELOADED lib
+ // and the value given from the lib is returned.
+ eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, "54321");
+#endif
+}
+
+
+// ld_config_test_helper must fail because it is depending on a lib which is not
+// in the search path
+//
+// Call sequence is...
+// _helper -- (get_value_from_lib()) -->
+// _lib1.so -- (get_value_from_another_lib()) -->
+// _lib2.so (returns 12345)
+// The two libs are in ns2/ subdir.
+TEST(dl, exec_without_ld_config_file) {
+#if defined(__BIONIC__)
+ std::string error_message = "CANNOT LINK EXECUTABLE \"" + get_testlib_root() + "/ld_config_test_helper/ld_config_test_helper\": library \"ld_config_test_helper_lib1.so\" not found\n";
+ std::string helper = get_testlib_root() +
+ "/ld_config_test_helper/ld_config_test_helper";
+ chmod(helper.c_str(), 0755);
+ ExecTestHelper eth;
+ eth.SetArgs({ helper.c_str(), nullptr });
+ eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, -6, error_message.c_str());
+#endif
+}
+
+#if defined(__BIONIC__)
+static void create_ld_config_file(std::string& config_file) {
+ std::ofstream fout(config_file.c_str(), std::ios::out);
+ fout << "dir.test = " << get_testlib_root() << "/ld_config_test_helper/" << std::endl
+ << "[test]" << std::endl
+ << "additional.namespaces = ns2" << std::endl
+ << "namespace.default.search.paths = " << get_testlib_root() << std::endl
+ << "namespace.default.links = ns2" << std::endl
+ << "namespace.default.link.ns2.shared_libs = libc.so:libm.so:libdl.so:ld_config_test_helper_lib1.so" << std::endl
+ << "namespace.ns2.search.paths = /system/${LIB}:" << get_testlib_root() << "/ns2" << std::endl;
+ fout.close();
+}
+#endif
+
+#ifdef USE_LD_CONFIG_FILE
+
+// _lib1.so and _lib2.so are now searchable by having another namespace 'ns2'
+// whose search paths include the 'ns2/' subdir.
+TEST(dl, exec_with_ld_config_file) {
+#if defined(__BIONIC__)
+ std::string helper = get_testlib_root() +
+ "/ld_config_test_helper/ld_config_test_helper";
+ std::string config_file = get_testlib_root() + "/ld.config.txt";
+ create_ld_config_file(config_file);
+ std::string env = std::string("LD_CONFIG_FILE=") + config_file;
+ chmod(helper.c_str(), 0755);
+ ExecTestHelper eth;
+ eth.SetArgs({ helper.c_str(), nullptr });
+ eth.SetEnv({ env.c_str(), nullptr });
+ eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, "12345");
+#endif
+}
+
+// _lib3.so has same symbol as lib2.so but returns 54321. _lib3.so is
+// LD_PRELOADed. This test is to ensure LD_PRELOADed libs are available to
+// additional namespaces other than the default namespace.
+TEST(dl, exec_with_ld_config_file_with_ld_preload) {
+#if defined(__BIONIC__)
+ std::string helper = get_testlib_root() +
+ "/ld_config_test_helper/ld_config_test_helper";
+ std::string config_file = get_testlib_root() + "/ld.config.txt";
+ create_ld_config_file(config_file);
+ std::string env = std::string("LD_CONFIG_FILE=") + config_file;
+ std::string env2 = std::string("LD_PRELOAD=") + get_testlib_root() + "/ld_config_test_helper_lib3.so";
+ chmod(helper.c_str(), 0755);
+ ExecTestHelper eth;
+ eth.SetArgs({ helper.c_str(), nullptr });
+ eth.SetEnv({ env.c_str(), env2.c_str(), nullptr });
+ eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, "54321");
+#endif
+}
+
+#endif // USE_LD_CONFIG_FILE
+
+// ensures that LD_CONFIG_FILE env var does not work for production builds.
+// The test input is the same as exec_with_ld_config_file, but it must fail in
+// this case.
+TEST(dl, disable_ld_config_file) {
+#if defined(__BIONIC__)
+ if (getuid() == 0) {
+ // when executed from the shell (e.g. not as part of CTS), skip the test.
+ // This test is only for CTS.
+ return;
+ }
+ std::string error_message = "CANNOT LINK EXECUTABLE \"" + get_testlib_root() + "/ld_config_test_helper/ld_config_test_helper\": library \"ld_config_test_helper_lib1.so\" not found\n";
+ std::string helper = get_testlib_root() +
+ "/ld_config_test_helper/ld_config_test_helper";
+ std::string config_file = get_testlib_root() + "/ld.config.txt";
+ create_ld_config_file(config_file);
+ std::string env = std::string("LD_CONFIG_FILE=") + config_file;
+ chmod(helper.c_str(), 0755);
+ ExecTestHelper eth;
+ eth.SetArgs({ helper.c_str(), nullptr });
+ eth.SetEnv({ env.c_str(), nullptr });
+ eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, -6, error_message.c_str());
+#endif
+}
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index b264e53..0dc54d0 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -824,7 +824,7 @@
const std::string lib_path = get_testlib_root() + "/libtest_simple.so";
int tmpfd = TEMP_FAILURE_RETRY(
- open(get_testlib_root().c_str(), O_TMPFILE | O_CLOEXEC | O_RDWR | O_EXCL));
+ open(get_testlib_root().c_str(), O_TMPFILE | O_CLOEXEC | O_RDWR | O_EXCL, 0));
// Ignore kernels without O_TMPFILE flag support
if (tmpfd == -1 && (errno == EISDIR || errno == EINVAL || errno == EOPNOTSUPP)) {
diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp
index 1bef0f4..4532a4b 100644
--- a/tests/fcntl_test.cpp
+++ b/tests/fcntl_test.cpp
@@ -23,6 +23,8 @@
#include "TemporaryFile.h"
+#include <android-base/stringprintf.h>
+
// Glibc v2.19 doesn't include these in fcntl.h so host builds will fail without.
#if !defined(FALLOC_FL_PUNCH_HOLE) || !defined(FALLOC_FL_KEEP_SIZE)
#include <linux/falloc.h>
@@ -292,3 +294,43 @@
ASSERT_EQ(errno, EOPNOTSUPP);
}
}
+
+TEST(fcntl, open_O_TMPFILE_mode) {
+#if __BIONIC__ // Our glibc is too old for O_TMPFILE.
+ TemporaryDir dir;
+ // Without O_EXCL, we're allowed to give this a name later.
+ // (This is unrelated to the O_CREAT interaction with O_EXCL.)
+ const mode_t perms = S_IRUSR | S_IWUSR;
+ int fd = open(dir.dirname, O_TMPFILE | O_RDWR, perms);
+
+ // Ignore kernels without O_TMPFILE support (< 3.11).
+ if (fd == -1 && (errno == EISDIR || errno == EINVAL || errno == EOPNOTSUPP)) return;
+
+ ASSERT_TRUE(fd != -1) << strerror(errno);
+
+ // Does the fd claim to have the mode we set?
+ struct stat sb = {};
+ ASSERT_EQ(0, fstat(fd, &sb));
+ ASSERT_EQ(perms, (sb.st_mode & ~S_IFMT));
+
+ std::string final_path = android::base::StringPrintf("%s/named_now", dir.dirname);
+ ASSERT_EQ(0, linkat(AT_FDCWD, android::base::StringPrintf("/proc/self/fd/%d", fd).c_str(),
+ AT_FDCWD, final_path.c_str(),
+ AT_SYMLINK_FOLLOW));
+ ASSERT_EQ(0, close(fd));
+
+ // Does the resulting file claim to have the mode we set?
+ ASSERT_EQ(0, stat(final_path.c_str(), &sb));
+ ASSERT_EQ(perms, (sb.st_mode & ~S_IFMT));
+
+ // With O_EXCL, you're not allowed to add a name later.
+ fd = open(dir.dirname, O_TMPFILE | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
+ ASSERT_TRUE(fd != -1) << strerror(errno);
+ errno = 0;
+ ASSERT_EQ(-1, linkat(AT_FDCWD, android::base::StringPrintf("/proc/self/fd/%d", fd).c_str(),
+ AT_FDCWD, android::base::StringPrintf("%s/no_chance", dir.dirname).c_str(),
+ AT_SYMLINK_FOLLOW));
+ ASSERT_EQ(ENOENT, errno);
+ ASSERT_EQ(0, close(fd));
+#endif
+}
diff --git a/tests/fortify_compilation_test.cpp b/tests/fortify_compilation_test.cpp
index bf577f6..d859ef1 100644
--- a/tests/fortify_compilation_test.cpp
+++ b/tests/fortify_compilation_test.cpp
@@ -71,7 +71,7 @@
// NOLINTNEXTLINE(whitespace/line_length)
// GCC: warning: call to void* __builtin___memcpy_chk(void*, const void*, {{(long )?}}unsigned int, {{(long )?}}unsigned int) will always overflow destination buffer
- // CLANG: error: call to unavailable function 'memcpy': memcpy called with size bigger than buffer
+ // CLANG: error: 'memcpy' called with size bigger than buffer
memcpy(buf, "foobar", sizeof("foobar") + 100);
}
@@ -80,7 +80,7 @@
// NOLINTNEXTLINE(whitespace/line_length)
// GCC: warning: call to void* __builtin___memmove_chk(void*, const void*, {{(long )?}}unsigned int, {{(long )?}}unsigned int) will always overflow destination buffer
- // CLANG: error: call to unavailable function 'memmove': memmove called with size bigger than buffer
+ // CLANG: error: 'memmove' called with size bigger than buffer
memmove(buf, "foobar", sizeof("foobar"));
}
@@ -89,7 +89,7 @@
// NOLINTNEXTLINE(whitespace/line_length)
// GCC: warning: call to void* __builtin___memset_chk(void*, int, {{(long )?}}unsigned int, {{(long )?}}unsigned int) will always overflow destination buffer
- // CLANG: error: call to unavailable function 'memset': memset called with size bigger than buffer
+ // CLANG: error: 'memset' called with size bigger than buffer
memset(buf, 0, 6);
}
@@ -98,8 +98,13 @@
// NOLINTNEXTLINE(whitespace/line_length)
// GCC: warning: call to {{(char\* __builtin___strcpy_chk\(char\*, const char\*, unsigned int\))|(void\* __builtin___memcpy_chk\(void\*, const void\*, (long )?unsigned int, (long )?unsigned int\))}} will always overflow destination buffer
- // CLANG: error: call to unavailable function 'strcpy': strcpy called with string bigger than buffer
+ // CLANG: error: 'strcpy' called with string bigger than buffer
strcpy(buf, "foobar"); // NOLINT(runtime/printf)
+
+ // NOLINTNEXTLINE(whitespace/line_length)
+ // GCC: warning: call to {{(char\* __builtin___strcpy_chk\(char\*, const char\*, unsigned int\))|(void\* __builtin___memcpy_chk\(void\*, const void\*, (long )?unsigned int, (long )?unsigned int\))}} will always overflow destination buffer
+ // CLANG: error: 'strcpy' called with string bigger than buffer
+ strcpy(buf, "quux");
}
void test_stpcpy() {
@@ -107,8 +112,13 @@
// NOLINTNEXTLINE(whitespace/line_length)
// GCC: warning: call to char* __builtin___stpcpy_chk(char*, const char*, {{(long )?}}unsigned int) will always overflow destination buffer
- // CLANG: error: call to unavailable function 'stpcpy': stpcpy called with string bigger than buffer
+ // CLANG: error: 'stpcpy' called with string bigger than buffer
stpcpy(buf, "foobar");
+
+ // NOLINTNEXTLINE(whitespace/line_length)
+ // GCC: warning: call to char* __builtin___stpcpy_chk(char*, const char*, {{(long )?}}unsigned int) will always overflow destination buffer
+ // CLANG: error: 'stpcpy' called with string bigger than buffer
+ stpcpy(buf, "quux");
}
void test_strncpy() {
@@ -214,14 +224,28 @@
void test_open() {
// NOLINTNEXTLINE(whitespace/line_length)
- // GCC: error: call to '__creat_missing_mode' declared with attribute error: called with O_CREAT, but missing mode
- // CLANG: error: 'open' called with O_CREAT, but missing mode
+ // GCC: error: call to '__creat_missing_mode' declared with attribute error: called with O_CREAT or O_TMPFILE, but missing mode
+ // CLANG: error: 'open' called with O_CREAT or O_TMPFILE, but missing mode
open("/dev/null", O_CREAT);
+ // GCC: error: call to '__creat_missing_mode' declared with attribute error: called with O_CREAT or O_TMPFILE, but missing mode
+ // CLANG: error: 'open' called with O_CREAT or O_TMPFILE, but missing mode
+ open("/dev/null", O_TMPFILE);
+
// NOLINTNEXTLINE(whitespace/line_length)
// GCC: error: call to '__creat_too_many_args' declared with attribute error: too many arguments
// CLANG: error: call to unavailable function 'open': too many arguments
open("/dev/null", O_CREAT, 0, 0);
+
+ // GCC: error: call to '__creat_too_many_args' declared with attribute error: too many arguments
+ // CLANG: error: call to unavailable function 'open': too many arguments
+ open("/dev/null", O_TMPFILE, 0, 0);
+
+ // CLANG: warning: 'open' has superfluous mode bits; missing O_CREAT?
+ open("/dev/null", O_RDONLY, 0644);
+
+ // CLANG: warning: 'open' has superfluous mode bits; missing O_CREAT?
+ open("/dev/null", O_DIRECTORY, 0644);
}
void test_poll() {
@@ -318,7 +342,7 @@
void test_memset_args_flipped() {
char from[4] = {0};
// NOLINTNEXTLINE(whitespace/line_length)
- // CLANG: 'memset' is deprecated: will set 0 bytes; maybe the arguments got flipped? (Add __bionic_zero_size_is_okay as a fourth argument to silence this.)
+ // CLANG: 'memset' will set 0 bytes; maybe the arguments got flipped?
memset(from, sizeof(from), 0);
}
diff --git a/tests/fortify_test.cpp b/tests/fortify_test.cpp
index 984a657..2946e23 100644
--- a/tests/fortify_test.cpp
+++ b/tests/fortify_test.cpp
@@ -985,3 +985,15 @@
timeout.tv_sec = timeout.tv_nsec = 0;
ASSERT_FORTIFY(ppoll(buf, fd_count, &timeout, NULL));
}
+
+TEST_F(DEATHTEST, open_O_CREAT_without_mode_fortified) {
+ int flags = O_CREAT; // Fool the compiler.
+ ASSERT_FORTIFY(open("", flags));
+}
+
+TEST_F(DEATHTEST, open_O_TMPFILE_without_mode_fortified) {
+#if __BIONIC__ // Our glibc is too old for O_TMPFILE.
+ int flags = O_TMPFILE; // Fool the compiler.
+ ASSERT_FORTIFY(open("", flags));
+#endif
+}
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 973a8d2..c1600cc 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -617,3 +617,59 @@
defaults: ["bionic_testlib_defaults"],
srcs: ["preinit_syscall_test_helper.cpp"],
}
+
+cc_test {
+ name: "ld_preload_test_helper",
+ host_supported: false,
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["ld_preload_test_helper.cpp"],
+ shared_libs: ["ld_preload_test_helper_lib1"],
+ ldflags: ["-Wl,--rpath,${ORIGIN}/.."],
+}
+
+cc_test_library {
+ name: "ld_preload_test_helper_lib1",
+ host_supported: false,
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["ld_preload_test_helper_lib1.cpp"],
+}
+
+cc_test_library {
+ name: "ld_preload_test_helper_lib2",
+ host_supported: false,
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["ld_preload_test_helper_lib2.cpp"],
+}
+
+cc_test {
+ name: "ld_config_test_helper",
+ host_supported: false,
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["ld_config_test_helper.cpp"],
+ shared_libs: ["ld_config_test_helper_lib1"],
+ ldflags: ["-Wl,--rpath,${ORIGIN}/.."],
+}
+
+cc_test_library {
+ name: "ld_config_test_helper_lib1",
+ host_supported: false,
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["ld_config_test_helper_lib1.cpp"],
+ shared_libs: ["ld_config_test_helper_lib2"],
+ relative_install_path: "/ns2",
+}
+
+cc_test_library {
+ name: "ld_config_test_helper_lib2",
+ host_supported: false,
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["ld_config_test_helper_lib2.cpp"],
+ relative_install_path: "/ns2",
+}
+
+cc_test_library {
+ name: "ld_config_test_helper_lib3",
+ host_supported: false,
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["ld_config_test_helper_lib3.cpp"],
+}
diff --git a/tests/libs/ld_config_test_helper.cpp b/tests/libs/ld_config_test_helper.cpp
new file mode 100644
index 0000000..592e8c0
--- /dev/null
+++ b/tests/libs/ld_config_test_helper.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+extern int get_value_from_lib();
+
+int main() {
+ printf("%d", get_value_from_lib());
+ return 0;
+}
diff --git a/tests/libs/ld_config_test_helper_lib1.cpp b/tests/libs/ld_config_test_helper_lib1.cpp
new file mode 100644
index 0000000..fc5401a
--- /dev/null
+++ b/tests/libs/ld_config_test_helper_lib1.cpp
@@ -0,0 +1,4 @@
+extern int get_value_from_another_lib();
+int get_value_from_lib() {
+ return get_value_from_another_lib();
+}
diff --git a/tests/libs/ld_config_test_helper_lib2.cpp b/tests/libs/ld_config_test_helper_lib2.cpp
new file mode 100644
index 0000000..a620a6c
--- /dev/null
+++ b/tests/libs/ld_config_test_helper_lib2.cpp
@@ -0,0 +1,3 @@
+int get_value_from_another_lib() {
+ return 12345;
+}
diff --git a/tests/libs/ld_config_test_helper_lib3.cpp b/tests/libs/ld_config_test_helper_lib3.cpp
new file mode 100644
index 0000000..93d1cd8
--- /dev/null
+++ b/tests/libs/ld_config_test_helper_lib3.cpp
@@ -0,0 +1,3 @@
+int get_value_from_another_lib() {
+ return 54321;
+}
diff --git a/tests/libs/ld_preload_test_helper.cpp b/tests/libs/ld_preload_test_helper.cpp
new file mode 100644
index 0000000..592e8c0
--- /dev/null
+++ b/tests/libs/ld_preload_test_helper.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+extern int get_value_from_lib();
+
+int main() {
+ printf("%d", get_value_from_lib());
+ return 0;
+}
diff --git a/tests/libs/ld_preload_test_helper_lib1.cpp b/tests/libs/ld_preload_test_helper_lib1.cpp
new file mode 100644
index 0000000..74e89db
--- /dev/null
+++ b/tests/libs/ld_preload_test_helper_lib1.cpp
@@ -0,0 +1,3 @@
+int get_value_from_lib() {
+ return 12345;
+}
diff --git a/tests/libs/ld_preload_test_helper_lib2.cpp b/tests/libs/ld_preload_test_helper_lib2.cpp
new file mode 100644
index 0000000..9239891
--- /dev/null
+++ b/tests/libs/ld_preload_test_helper_lib2.cpp
@@ -0,0 +1,3 @@
+int get_value_from_lib() {
+ return 54321;
+}
diff --git a/tests/sched_test.cpp b/tests/sched_test.cpp
index a4cffc0..e70528e 100644
--- a/tests/sched_test.cpp
+++ b/tests/sched_test.cpp
@@ -270,3 +270,34 @@
CPU_FREE(set1);
CPU_FREE(set2);
}
+
+TEST(sched, sched_get_priority_min_sched_get_priority_max) {
+ EXPECT_LE(sched_get_priority_min(SCHED_BATCH), sched_get_priority_max(SCHED_BATCH));
+ EXPECT_LE(sched_get_priority_min(SCHED_FIFO), sched_get_priority_max(SCHED_FIFO));
+ EXPECT_LE(sched_get_priority_min(SCHED_IDLE), sched_get_priority_max(SCHED_IDLE));
+ EXPECT_LE(sched_get_priority_min(SCHED_OTHER), sched_get_priority_max(SCHED_OTHER));
+ EXPECT_LE(sched_get_priority_min(SCHED_RR), sched_get_priority_max(SCHED_RR));
+}
+
+TEST(sched, sched_getscheduler_sched_setscheduler) {
+ // POSIX: "If pid is zero, the scheduling policy shall be returned for the
+ // calling process".
+ ASSERT_EQ(sched_getscheduler(getpid()), sched_getscheduler(0));
+
+ const int original_policy = sched_getscheduler(getpid());
+ sched_param p = {};
+ p.sched_priority = sched_get_priority_min(original_policy);
+ errno = 0;
+ ASSERT_EQ(-1, sched_setscheduler(getpid(), INT_MAX, &p));
+ ASSERT_EQ(EINVAL, errno);
+
+ ASSERT_EQ(0, sched_getparam(getpid(), &p));
+ ASSERT_EQ(original_policy, sched_setscheduler(getpid(), SCHED_BATCH, &p));
+ // POSIX says this should return the previous policy (here SCHED_BATCH),
+ // but the Linux system call doesn't, and the glibc wrapper doesn't correct
+ // this (the "returns 0" behavior is even documented on the man page in
+ // the BUGS section). This was our historical behavior too, so in the
+ // absence of reasons to break compatibility with ourselves and glibc, we
+ // don't behave as POSIX specifies. http://b/26203902.
+ ASSERT_EQ(0, sched_setscheduler(getpid(), original_policy, &p));
+}